import {cellStarts, cellForced, defaultRenderCell, treeCellPrefix} from './config';
import {mergeOptions, parseWidth, parseMinWidth, compose} from './util';
import ElCheckbox from 'element-ui/packages/checkbox';

let columnIdSeed = 1;

export default {
    name: 'ElTableColumn',

    props: {
        type: {
            type: String,
            default: 'default'
        },
        label: String,
        className: String,
        labelClassName: String,
        property: String,
        prop: String,
        width: {},
        minWidth: {},
        renderHeader: Function,
        sortable: {
            type: [Boolean, String],
            default: false
        },
        sortMethod: Function,
        sortBy: [String, Function, Array],
        resizable: {
            type: Boolean,
            default: true
        },
        columnKey: String,
        align: String,
        headerAlign: String,
        showTooltipWhenOverflow: Boolean,
        showOverflowTooltip: Boolean,
        fixed: [Boolean, String],
        formatter: Function,
        selectable: Function,
        reserveSelection: Boolean,
        filterMethod: Function,
        filteredValue: Array,
        filters: Array,
        filterPlacement: String,
        filterMultiple: {
            type: Boolean,
            default: true
        },
        index: [Number, Function],
        sortOrders: {
            type: Array,
            default() {
                return ['ascending', 'descending', null];
            },
            validator(val) {
                return val.every(order => ['ascending', 'descending', null].indexOf(order) > -1);
            }
        }
    },

    data() {
        return {
            isSubColumn: false,
            columns: []
        };
    },

    computed: {
        owner() {
            let parent = this.$parent;
            while (parent && !parent.tableId) {
                parent = parent.$parent;
            }
            return parent;
        },

        columnOrTableParent() {
            let parent = this.$parent;
            while (parent && !parent.tableId && !parent.columnId) {
                parent = parent.$parent;
            }
            return parent;
        },

        realWidth() {
            return parseWidth(this.width);
        },

        realMinWidth() {
            return parseMinWidth(this.minWidth);
        },

        realAlign() {
            return this.align ? 'is-' + this.align : null;
        },

        realHeaderAlign() {
            return this.headerAlign ? 'is-' + this.headerAlign : this.realAlign;
        }
    },

    methods: {
        getPropsData(...props) {
            return props.reduce((prev, cur) => {
                if (Array.isArray(cur)) {
                    cur.forEach((key) => {
                        prev[key] = this[key];
                    });
                }
                return prev;
            }, {});
        },

        getColumnElIndex(children, child) {
            return [].indexOf.call(children, child);
        },

        setColumnWidth(column) {
            if (this.realWidth) {
                column.width = this.realWidth;
            }
            if (this.realMinWidth) {
                column.minWidth = this.realMinWidth;
            }
            if (!column.minWidth) {
                column.minWidth = 80;
            }
            column.realWidth = column.width === undefined ? column.minWidth : column.width;
            return column;
        },

        setColumnForcedProps(column) {
            // 对于特定类型的 column，某些属性不允许设置
            const type = column.type;
            const source = cellForced[type] || {};
            Object.keys(source).forEach(prop => {
                let value = source[prop];
                if (value !== undefined) {
                    column[prop] = prop === 'className' ? `${column[prop]} ${value}` : value;
                }
            });
            return column;
        },

        setColumnRenders(column) {
            // renderHeader 属性不推荐使用。
            if (this.renderHeader) {
                console.warn('[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.');
            } else if (column.type !== 'selection') {
                column.renderHeader = (h, scope) => {
                    const renderHeader = this.$scopedSlots.header;
                    return renderHeader ? renderHeader(scope) : column.label;
                };
            }

            let originRenderCell = column.renderCell;
            // TODO: 这里的实现调整
            if (column.type === 'expand') {
                // 对于展开行，renderCell 不允许配置的。在上一步中已经设置过，这里需要简单封装一下。
                column.renderCell = (h, data) => ( < div
            class
                = "cell" >
                    {originRenderCell(h, data)}
                    < /div>);
                this.owner.renderExpanded = (h, data) => {
                    return this.$scopedSlots.default
                        ? this.$scopedSlots.default(data)
                        : this.$slots.default;
                };
            } else {
                originRenderCell = originRenderCell || defaultRenderCell;
                // 对 renderCell 进行包装
                column.renderCell = (h, data) => {
                    let children = null;
                    if (this.$scopedSlots.default) {
                        children = this.$scopedSlots.default(data);
                    } else {
                        children = originRenderCell(h, data);
                    }
                    const prefix = treeCellPrefix(h, data);
                    const props = {
                        class: 'cell',
                        style: {}
                    };
                    if (column.showOverflowTooltip) {
                        props.class += ' el-tooltip';
                        props.style = {width: (data.column.realWidth || data.column.width) - 1 + 'px'};
                    }
                    return ( < div
                    { ...
                        props
                    }
                >
                    {
                        prefix
                    }
                    {
                        children
                    }
                <
                    /div>);
                };
            }
            return column;
        },

        registerNormalWatchers() {
            const props = ['label', 'property', 'filters', 'filterMultiple', 'sortable', 'index', 'formatter', 'className', 'labelClassName', 'showOverflowTooltip'];
            // 一些属性具有别名
            const aliases = {
                prop: 'property',
                realAlign: 'align',
                realHeaderAlign: 'headerAlign',
                realWidth: 'width'
            };
            const allAliases = props.reduce((prev, cur) => {
                prev[cur] = cur;
                return prev;
            }, aliases);

            Object.keys(allAliases).forEach(key => {
                const columnKey = aliases[key];

                this.$watch(key, (newVal) => {
                    this.columnConfig[columnKey] = newVal;
                });
            });
        },

        registerComplexWatchers() {
            const props = ['fixed'];
            const aliases = {
                realWidth: 'width',
                realMinWidth: 'minWidth'
            };
            const allAliases = props.reduce((prev, cur) => {
                prev[cur] = cur;
                return prev;
            }, aliases);

            Object.keys(allAliases).forEach(key => {
                const columnKey = aliases[key];

                this.$watch(key, (newVal) => {
                    this.columnConfig[columnKey] = newVal;
                    const updateColumns = columnKey === 'fixed';
                    this.owner.store.scheduleLayout(updateColumns);
                });
            });
        }
    },

    components: {
        ElCheckbox
    },

    beforeCreate() {
        this.row = {};
        this.column = {};
        this.$index = 0;
        this.columnId = '';
    },

    created() {
        const parent = this.columnOrTableParent;
        this.isSubColumn = this.owner !== parent;
        this.columnId = (parent.tableId || parent.columnId) + '_column_' + columnIdSeed++;

        const type = this.type || 'default';
        const sortable = this.sortable === '' ? true : this.sortable;
        const defaults = {
            ...cellStarts[type],
            id: this.columnId,
            type: type,
            property: this.prop || this.property,
            align: this.realAlign,
            headerAlign: this.realHeaderAlign,
            showOverflowTooltip: this.showOverflowTooltip || this.showTooltipWhenOverflow,
            // filter 相关属性
            filterable: this.filters || this.filterMethod,
            filteredValue: [],
            filterPlacement: '',
            isColumnGroup: false,
            filterOpened: false,
            // sort 相关属性
            sortable: sortable,
            // index 列
            index: this.index
        };

        const basicProps = ['columnKey', 'label', 'className', 'labelClassName', 'type', 'renderHeader', 'formatter', 'fixed', 'resizable'];
        const sortProps = ['sortMethod', 'sortBy', 'sortOrders'];
        const selectProps = ['selectable', 'reserveSelection'];
        const filterProps = ['filterMethod', 'filters', 'filterMultiple', 'filterOpened', 'filteredValue', 'filterPlacement'];

        let column = this.getPropsData(basicProps, sortProps, selectProps, filterProps);
        column = mergeOptions(defaults, column);

        // 注意 compose 中函数执行的顺序是从右到左
        const chains = compose(this.setColumnRenders, this.setColumnWidth, this.setColumnForcedProps);
        column = chains(column);

        this.columnConfig = column;

        // 注册 watcher
        this.registerNormalWatchers();
        this.registerComplexWatchers();
    },

    mounted() {
        const owner = this.owner;
        const parent = this.columnOrTableParent;
        const children = this.isSubColumn ? parent.$el.children : parent.$refs.hiddenColumns.children;
        const columnIndex = this.getColumnElIndex(children, this.$el);

        owner.store.commit('insertColumn', this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
    },

    destroyed() {
        if (!this.$parent) return;
        const parent = this.$parent;
        this.owner.store.commit('removeColumn', this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
    },

    render(h) {
        // slots 也要渲染，需要计算合并表头
        return h('div', this.$slots.default);
    }
};
